import time
import unittest
from threading import Thread, Lock
from Common.MyUnit import MyTest
from Common.Route import Any_Path
from Common.DataHandle import Package_Data, Get_Skip, SqlHandle, Case_data, GetRedis
from Common.ImportClass import ImportClass
from Common.MySql import Sql
import os
import sys
from Common.FontColor import outcome
from Common.MyRedis import ReDis
import requests
from Common.Results import Delete_file
from Common.Log import MyLog
from Common.MyProcess import MyProcess
from Common.ReadYaml import ConfigYaml, CaseYaml
from Common.SendMail import MyMail
from Common.MyProcess import RunFailError
from Common.QqWatch import Send_Wechat
from Common.Login import Login

log = MyLog()
from Common.RwYaml import RwYaml
from Common.SendFeiShu import FeiShu

edition = ConfigYaml('edition').report
science = ConfigYaml('science').report
server_ip = ConfigYaml('serverip').base_config
server_port = ConfigYaml('serverport').base_config

send_msg = {
    "msgtype": "markdown",
    "markdown": {
        "content": ""
    }
}


class MyThread(Thread):
    '''
    重写多线程方法
    '''

    def __init__(self, moudle, data=None):
        Thread.__init__(self)
        self.moudle = moudle  # 目录名称,所要运行的那个目录
        self.data = data
        self.lock = Lock()  # 示例锁对象，获取对象id

    def run(self):
        '''
        重写run方法
        :return:
        '''
        log.info("开启多线程并进行加锁....")
        self.lock.acquire()
        RunClass(self.moudle, self.data).run_moudle()
        self.lock.release()
        log.info("多线程结束释放锁....")


class RunClass(object):

    def __init__(self, moudle, data=None):
        '''
        运行单个类
        :param moudle:
        '''
        self.moudle = moudle
        self.data = data

    def run_moudle(self):
        '''
        :return:
        '''
        log.info('开始运行单个模块用例...')
        runner = unittest.TextTestRunner(verbosity=1)
        result = runner.run(MyTest.parametrize(self.moudle))
        Get_Skip(result.skipped, self.data).get_skip()
        log.info('运行单个模块用例结束...')


class RunAll:

    def __init__(self, base_url, report='report.html', encoding='utf-8', datafile="Data.yaml"):
        '''
        运行所有用例
        :param report:    报告名称 ，存放地址template目录下
        :param encoding:   编码格式
        '''
        title = "{}(环境)ERP接口自动化测试报告"
        self.projectName = ConfigYaml("projectName").base_config  # 工程名称
        rw = RwYaml()
        if base_url == "qa":
            rw.write_yaml("base_url", domain_name="http://erp-web.qa.erp.starlinke.tech/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.107")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("qa", self.projectName))

        elif base_url == "qa2":
            rw.write_yaml("base_url", domain_name="http://erp-web.qa2.erp.starlinke.tech/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.105")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("qa2", self.projectName))

        elif base_url == "qa3":
            rw.write_yaml("base_url", domain_name="http://erp-web.qa3.erp.starlinke.tech/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.106")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("qa3", self.projectName))

        elif base_url == "qa4":
            rw.write_yaml("base_url", domain_name="http://erp-web.qa4.erp.starlinke.tech/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.104")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("qa4", self.projectName))

        elif base_url == "qa5":
            rw.write_yaml("base_url", domain_name="http://erp-web.qa5.erp.starlinke.tech/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.130")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("qa5", self.projectName))

        elif base_url == "autom":
            rw.write_yaml("base_url", domain_name="http://erp-web.autom.erp.starlinke.tech/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.118")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("autom", self.projectName))

        elif base_url == "alpha":
            rw.write_yaml("base_url", domain_name="http://alpha.erp.starlinke.cn/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo01")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="172.28.188.118")
            rw.write_yaml("base_config", testsql_port=3306)
            rw.write_yaml("base_config", testsql_user="erp_test")
            rw.write_yaml("base_config", testsql_pwd="localfSdCEi^qVwj44g$Rr")
            rw.write_yaml("report", title=title.format("alpha", self.projectName))

        elif base_url == "beta":
            rw.write_yaml("base_url", domain_name="http://beta.erp.starlinke.cn/api/v1.0")
            rw.write_yaml("base_config", shippingChannelId=437)
            rw.write_yaml("base_config", shippingChannelName="美国专属")
            rw.write_yaml("base_config", shippingChannelCode="QQLD374")
            rw.write_yaml("base_config", shippingProviderId=3)
            rw.write_yaml("base_config", shippingProviderName="全球立达")
            rw.write_yaml("base_config", shippingProviderCode="ld")
            rw.write_yaml("base_config", login_user="chenjianbo")
            rw.write_yaml("base_config", login_pwd="111111")
            rw.write_yaml("base_config", testsql_host="open-erp-beta.mysql.rds.aliyuncs.com")
            rw.write_yaml("base_config", testsql_port=33006)
            rw.write_yaml("base_config", testsql_user="erp_beta")
            rw.write_yaml("base_config", testsql_pwd="wbE0JR2fLKr6XZzo")
            rw.write_yaml("report", title=title.format("beta", self.projectName))

        self.report = report
        self.encoding = encoding
        self.datafile = datafile
        self.domain = ConfigYaml('domain').base_config  # 域名
        self.title = ConfigYaml('title').base_config  # 标题
        self.EnvName = ConfigYaml('title').base_config  # 环境
        self.moudleName = ConfigYaml('moudleName').base_config  # 运行的模块名称
        self.matching = ConfigYaml('matching').base_config  # 文件后缀样式
        self.thread_count = ConfigYaml('thread_count').base_config  # 开启线程
        self.serverip = ConfigYaml('serverip').base_config  # 接口服务器ip，及测试报告的服务器ip
        self.serverport = ConfigYaml('serverport').base_config  # 服务端口
        self.fei_shu_send = ConfigYaml('fei_shu_send').base_config  # 是否发送飞书消息
        self.delsql = ConfigYaml('del_response').sql  # 清空数据
        self.search_sql = ConfigYaml('search_response').sql  # 查询数据
        self.search_desc = ConfigYaml('search_desc').sql  # 按降序查询数据（time）
        self.insert_status = ConfigYaml('insert_status').sql  # 插入汇总表语句
        self.status_max_id = ConfigYaml('search_status').sql  # 查询汇总表最大id
        self.search_sum_time = ConfigYaml('search_sum_time').sql  # 查询总共用时
        self.case_number = ConfigYaml('search_response_case').sql  # 查询response表中的总数
        self.response_max_usetime = ConfigYaml('search_max_time').sql  # 查询最大时间
        self.search_success_fail = ConfigYaml('search_success_fail').sql
        self.copy_response = ConfigYaml('insert_history').sql  # 拷贝历史数据
        self.thread = ConfigYaml('threadrun').base_config  # 是否开启多线程运行
        self.process = ConfigYaml('process').base_config  # 是否开启多进程运行
        case_file_list = [file for file in os.listdir(self.projectName) if file != self.datafile and '.yaml' in file]
        self.data = {}
        for case_file in case_file_list:
            self.data.update(CaseYaml(file=case_file).all_case)  # 获取用例所有数据
        self.sql = ConfigYaml('sql').base_config  # 是否开启mysql存储数据
        self.redis = ConfigYaml('redis').base_config  # 是否开始redis存储数据
        self.mail = ConfigYaml('Mail').base_config
        self.wechat = ConfigYaml('Wechat').base_config
        self.eachtimes = ConfigYaml('eachtimes').base_config  # 运行次数
        self.search_max_result = ConfigYaml('search_max_result').sql  # 查询最大数字
        self.operatmode = ConfigYaml('operatmode').base_config  # 选择执行方式，
        self.basenumber = ConfigYaml('basenumber').base_config  # 执行次数，基数
        self.runfrequency = ConfigYaml('runfrequency').base_config  # 只运行失败和错误的用例次数
        self.againrunall = ConfigYaml('againrun').base_config  # 运行失败和错误的用例多少次数之后再整体运行多少次
        self.report_path = Any_Path("template", 'report.html')  # 测试报告存放路径
        self.oldstrcs = '/static/mycss.css'  # 静态文件地址css
        self.oldstrjs = '/static/alljs.js'  # 静态js文件地址
        self.newstrcs = '../static/mycss.css'
        self.newstrjs = '../static/alljs.js'
        if self.domain:
            self.url = 'http://{}/result_report/'.format(self.domain)
        else:
            self.url = 'http://{}:{}/result_report/'.format(self.serverip, self.serverport)

        ImportClass().moudle_write()
        Login().write_token()

    def runallmodul(self):
        '''
        非多线程运行
        :return:
        '''

        log.info("单线程用例执行开始....")
        if self.moudleName:
            self.current_path = Any_Path(self.projectName, self.moudleName)
        else:
            self.current_path = Any_Path(self.projectName)
        discover = unittest.defaultTestLoader.discover(
            self.current_path, pattern=self.matching, top_level_dir=None
        )
        runner = unittest.TextTestRunner(verbosity=1)
        result = runner.run(discover)
        log.info("单线程用例执行完成....")
        Get_Skip(result.skipped, self.data).get_skip()

    def runthread(self):
        '''
        多线程运行
        :return:
        '''
        from ERP import all_class
        mythreads = []
        for mythread in all_class:
            mythreads.append(MyThread(mythread, self.data))

        for start in mythreads:
            start.start()

        for end in mythreads:
            end.join()

    def run_fail_error(self, allclass, classcase):
        '''
        运行失败或者错误率达到多少的
        :return:
        '''
        RunFailError(allclass, classcase).run_fail_error()

    def runprocess(self):
        '''
        多进程运行
        :return:
        '''
        from ERP import all_dirs
        myprocess = []
        for process in all_dirs:
            myprocess.append(MyProcess(process, self.data))

        for start in myprocess:
            start.start()

        for end in myprocess:
            end.join()

    def sql_handle(self, data):
        '''
        获取总共时间，和用时集合
        :return:
        '''
        all_time = []
        sumtime = 0
        if data:
            for times in data:
                if times[0] != 0:
                    all_time.append(times[0])
                    sumtime += float(times[0])

            return all_time, sumtime
        else:
            all_time = sumtime = 0
            return all_time, sumtime

    def runmethod(self):
        '''
        运行方法
        :return:
        '''

        log.info('开始运行用例....')
        if self.thread:
            self.runthread()
        elif self.process:
            self.runprocess()
        else:
            self.runallmodul()

    def runcase(self):
        '''
        运行用例
        :return:
        '''
        from ERP import all_class
        from ERP import class_case
        from ERP import fail_error
        self.startdata = time.strftime("%Y-%m-%d:%H:%M:%S")
        self.startime = time.time()
        max_number = Sql(self.search_max_result, switch=False).execute_sql()
        if max_number[0][0]:
            operatimes = max_number[0][0]
        else:
            operatimes = 0
        if self.operatmode == 0:  # 执行方式
            if operatimes % self.eachtimes == 0:
                self.runmethod()
            else:
                self.run_fail_error(all_class, class_case)

        elif self.operatmode == 1:
            deviation = operatimes - self.basenumber
            valuesum = self.runfrequency + self.againrunall
            if operatimes < self.basenumber:
                self.runmethod()

            elif (deviation - (deviation // valuesum) * valuesum) % valuesum <= self.runfrequency:
                self.run_fail_error(all_class, fail_error)

            else:
                self.runmethod()

        else:
            self.runmethod()
        log.info('用例运行结束....')
        self.enddata = time.strftime("%Y-%m-%d:%H:%M:%S")
        self.endtime = time.time()
        self.sumtime = round((self.endtime - self.startime), 2)
        return self.startdata, self.enddata, self.sumtime

    def collect_data(self, version, even):
        '''
        收集数据
        :return:
        status_id,version,science,total_case,duration,start_time,end_time,max_time,avg_time,success_case,fail_case,report_title
        '''
        title = ConfigYaml('title').report
        start_time, end_time, sum_time = self.runcase()
        success_sql = self.search_success_fail % ("成功")
        fail_sql = self.search_success_fail % ("失败")
        status_max_id = list(Sql(sql=self.status_max_id, switch=False).execute_sql())[0][0]
        case_number = list(Sql(sql=self.case_number, switch=False).execute_sql())[0][0]
        max_time = list(Sql(sql=self.response_max_usetime, switch=False).execute_sql())[0][0]
        all_case_sum_time = list(Sql(sql=self.search_sum_time, switch=False).execute_sql())[0][0]
        success_case = list(Sql(sql=success_sql, switch=False).execute_sql())[0][0]
        fail_case = list(Sql(sql=fail_sql, switch=False).execute_sql())[0][0]
        if status_max_id:
            current_id = status_max_id + 1  # 插入新的id
        else:
            current_id = 1

        if case_number:
            total_case = case_number
        else:
            total_case = 0

        if max_time:

            max_use_time = round(max_time, 4)
        else:
            max_use_time = 0

        if all_case_sum_time:
            avg_time = round(all_case_sum_time / total_case, 4)
        else:
            avg_time = 0

        if success_case:
            all_success_case = success_case
        else:
            all_success_case = 0

        if fail_case:
            all_fail_case = fail_case

        else:
            all_fail_case = 0

        insert_status = self.insert_status % (current_id, edition, science, total_case, sum_time, start_time,
                                              end_time, max_use_time, avg_time, all_success_case, all_fail_case,
                                              title)
        Sql(sql=insert_status, switch=False).execute_sql()

        self.copy_case_data(current_id)
        fei_shu_msg = f"{title}: \n version：{version}, \n 用例总数：{total_case}(条),\n 总共用时：{sum_time}(秒), \n" \
                      f" 成功总数：{all_success_case}(条),\n 失败总数：{all_fail_case}(条),\n " \
                      f"开始时间：{start_time},\n 结束时间：{end_time},\n " \
                      f"用时最长：{max_use_time}(秒),\n 平均用时：{avg_time}(秒),\n"

        sqlname = ConfigYaml('sqlname').base_config
        get_status_url = f"http://{server_ip}:{server_port}/return_status/?sqlname={sqlname}"
        try:
            r = requests.get(get_status_url, timeout=3000)
            if r.json().get("code") == 0:
                status_id = r.json().get("status")
            else:
                status_id = 0
        except:
            status_id = 0

        report_url = f"http://{server_ip}:{server_port}/result_report/?sqlname={sqlname}&status={status_id}"

        msg = "### 自动化测试报告通知消息：\n" \
              "**{}:**\n**version**：{}\n" \
              "**用例总数**：{}(条)\n" \
              "**总共用时**：{}(秒)\n" \
              "**成功总数**：{}(条)\n" \
              "**失败总数**：{}(条)\n" \
              "**开始时间**：{}\n" \
              "**结束时间**：{}\n" \
              "**用时最长**：{}(秒)\n" \
              "**平均用时**：{}(秒)\n" \
              "[**点击查看详情**]({})".format(title, version, total_case, sum_time, all_success_case, all_fail_case,
                                        start_time, end_time, max_use_time, avg_time, report_url)
        send_msg['markdown']['content'] = msg

        return send_msg, all_fail_case

    def copy_case_data(self, status):
        '''
        复制数据到另一张表
        :param report_path: 报告目录
        :param name: 报告名称
        :return:
        '''

        copy_response_sql = self.copy_response % (status)
        Sql(sql=copy_response_sql, switch=False).execute_sql()

    def get_report(self, version, even):
        '''
        发送数据到服务器
        :return:
        '''
        self.clean_data()
        msg, all_fail_case = self.collect_data(version, even)
        if self.fei_shu_send and all_fail_case:
            FeiShu().send_text(msg)

    def download_report(self, url):
        '''
        将服务器的测试报告下载到本地接口
        :return:
        '''
        if self.get_report:
            self.get_picture(url)
        log.info('下载测试报告至本地成功....')

        return

    def send_mail(self):
        '''
        发送邮件
        :return:
        '''

        self.clean_data()
        # url = self.url.replace("edit_config", "result_report")
        # self.download_report(url)

        if self.mail:
            outcome("green", "请稍后!正在发送邮件....")
            # MyMail(url, self.report_path).send_info()/

    def clean_data(self):
        '''
        运行前数据清理
        :return:
        '''

        if self.sql:
            Sql(self.delsql, switch=False).execute_sql()  # 清空response表
        if self.redis:
            ReDis().delete()  # 清空redis表
        Case_data().clear_content()  # 清空文件存储
        Delete_file().beforedata()  # 删除7天前的日志
        log.info("表创建及清空前置相关工作运行成功....")


if __name__ == '__main__':
    param = sys.argv
    feishu = ''.join(param[2:-1])
    RunAll(param[-1]).get_report(feishu, param[-1])

